package dse.modules;

import java.util.List;
import java.util.Map;
import java.util.Vector;

import dse.BloomFilter;
import dse.Cluster;
import dse.DataObject;
import dse.DseException;
import dse.ExperimentConfiguration;

/**
 * This module is responsible for creating the bloom filters that detail what
 * data objects a cluster is caching.
 * 
 * @author Aaron
 */
public class GeneralBloomFilterGenerator
implements BloomFilterGenerator,  BloomFilter.Hasher<DataObject> 
{
	private int m;
	private int hashesPerObject;
	private int [] hashBases;
	
	public void initalize (
			ExperimentConfiguration systemSettings,
			Map<String, String> moduleSettings
			)
	throws DseException
	{
		ModuleUtil.SettingsReader sr = ModuleUtil.getSettingsReader(
				this.getClass(), moduleSettings
				);
		m = sr.getInteger("m");
		hashesPerObject = sr.getInteger("hashes-per-object");
		
		hashBases = new int [hashesPerObject];
		for (int a = 0; a < hashesPerObject; a++)
			hashBases[a] = systemSettings.getRandom().nextInt();
	}
	
	public BloomFilter<DataObject> generateBloomFilterForCachedDataObjects (
			Cluster c
			)
	{
		BloomFilter<DataObject> bf = new BloomFilter<DataObject>(m, this);
		for (DataObject d : c.cachedDataObjects())
			bf.add(d);
		return bf;
	}

	public List<Integer> getHashBitsFor (int m, DataObject key) {
		Vector<Integer> bits = new Vector<Integer>();
		
		for (int a = 0; a < hashesPerObject; a++)
			bits.add(hash(a, m, key.id()));
		
		return bits;
	}
	
	private int hash (int baseIndex, int m, int v) {
		int x = hashBases[baseIndex] ^ (int)Math.pow(v+12, 2.43);
		x = x & 0x7FFFFFFF;
		
		assert x > 0;
		return x % m;
	}
}
